package baseFx.common.utils;

import baseFx.common.Stream;
import baseFx.common.caching.AppCache;
import baseFx.common.caching.Cache;
import baseFx.common.caching.CacheItem;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;

public class EnumUtils {
    private static Cache cache = new AppCache();

    public static <T> T parse(Class<T> clazz, String name) {
        if (clazz.isEnum() == false) {
            return null;
        }
        try {
            return (T) Enum.valueOf((Class<? extends Enum>) clazz, name);
        } catch (Exception e) {
            return null;
        }
    }

    public static List<String> names(Class<?> clazz) {
        if (clazz.isEnum() == false) {
            return null;
        }
        try {
            Method method = clazz.getMethod("values");
            Enum[] items = (Enum[]) method.invoke(null);
            return Stream.create(items).map(i -> i.name()).toList();
        } catch (Exception e) {
            return null;
        }
    }

    public static Integer getId(Enum e) {
        try {
            Field f = haveId(e.getClass());
            if (f == null) {
                return null;
            }
            return (Integer) f.get(e);
        } catch (Exception ex) {
            return null;
        }
    }

    public static <T> T parseById(Class<T> clazz, Integer id) {
        if (clazz.isEnum() == false || id == null) {
            return null;
        }
        Field f = haveId(clazz);
        if (f == null) {
            return null;
        }
        try {
            Method method = clazz.getMethod("values");
            T[] items = (T[]) method.invoke(null);
            return Stream.create(items).first(i -> {
                try {
                    return id.equals(f.get(i));
                } catch (IllegalAccessException e) {
                    return false;
                }
            }).orElse(null);
        } catch (Exception e) {
            return null;
        }
    }

    public static boolean isIdEnum(Class<?> clazz) {
        if (clazz.isEnum() == false) {
            return false;
        }
        return haveId(clazz) != null;
    }

    private static Field haveId(Class<?> clazz) {
        try {
            Boolean b = (Boolean) cache.get(clazz.getCanonicalName());
            if (b == null) {
                Field f = clazz.getDeclaredField("id");
                if (f != null &&
                        Modifier.isPublic(f.getModifiers()) &&
                        Modifier.isFinal(f.getModifiers()) &&
                        Modifier.isStatic(f.getModifiers()) == false &&
                        f.getType() == int.class) {
                    if (f.isAccessible() == false) {
                        f.setAccessible(true);
                    }
                } else {
                    f = null;
                }
                CacheItem item = new CacheItem();
                item.key = clazz.getCanonicalName();
                item.value = f != null;
                item.absoluteExpiration = FxDate.SECONDS * 60 * 60;
                cache.save(item);
                return f;
            } else if (b == true) {
                return clazz.getDeclaredField("id");
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }
}
